from .virtualaiv import VirtualAIV
from asyncio import sleep

class VirtualWharf(object):
    """
    虚拟码头类，对码头场景的仿真。模拟系统中扮演上位机的角色与后台进行通信
    + 控制所有车辆的运动
    + 获取所有车辆的信息
    + 推送码头发生的事件
    + 推送车辆的运动状态
    + ··· ···
    """
    def __init__(self, config):
        """
            参数如下
            - config 控制器基本配置，结构如下
            {
                'update_time': 场景刷新的时间间隔，单位（秒），默认 0.5
            }
        """
        # 初始化自身
        self.__update_time = config.get('update_time', 0.5)

        self.__now_time = 0
        self.__aivs = {}
        # 存放正在运动的无人车 id
        self.__moving_aivs = []
        # 存放场景中发生的所有事件
        self.__events_happened = []
        # 事件的有效期，单位为“更新周期”
        self.__outmode_time = 5
        # 事件回调
        self.emit_event = None

    def initialize(self, aiv_infos, tasks = []):
        '''
        初始化场景中的所有 AIV
        '''
        for aiv_info in aiv_infos:
            # 每辆车生成一个 id
            aiv_id = self.unique_id()
            # 以每辆车的 id 为键，将所有车存在字典里
            aiv_info['id'] = aiv_id
            self.__aivs[aiv_id] = VirtualAIV(aiv_info)
            # 绑定回调事件函数
            self.__aivs[aiv_id].emit_event = self.event_happend
        
        self.init_tasks = tasks
    
    async def update(self):
        '''
        周期性地刷新
        '''
        print('虚拟上位机已启动')
        while True:
            # 时间的更新
            self.__now_time += self.__update_time
            # 更新下位机（调度系统的时间）模块
            self.__emit('update-time', self.__now_time)
            # 车辆位置的更新
            self.__update_aivs()
            # 将最新的车辆信息推送给下位机
            self.__emit('update-aivs', self.aiv_infos)
            # 等待
            await sleep(self.__update_time)

            if self.init_tasks:
                self.__emit('add-tasks', self.init_tasks)
                self.init_tasks = None

    def unique_id(self) -> str:
        '''
        为每辆AIV生成独一无二的id
        '''
        return str(len(self.__aivs.items()))

    def event_happend(self, event, params):
        '''
        来自AIV上报的事件
        '''
        self.__events_happened.append({
            'time': self.now,
            'type': event,
            'detail': params
        })
        self.__emit(event, params)

    @property
    def now(self):
        return round(self.__now_time, 1)

    @property
    def aivs(self) -> list:
        return list(self.__aivs.values())

    @property
    def aiv_paths(self):
        '''
            正在运动的所有车辆的运行轨迹，点集的集合，结构如下
            [
                {
                    "AIVid": aiv_id,
                    "Pointarr": []
                },
                ...
            ]
        '''
        ts = []
        for aiv_id in self.__moving_aivs:
            ts.append({
                "AIVid": aiv_id,
                "Pointarr": self.__aivs[aiv_id].track
            })
        return ts

    @property
    def aiv_coordinates(self):
        '''
            所有无人车的当前位置，结构如下
            [
                {
                    'id': aiv_id,
                    'point': {
                        'x': x,
                        'y': y
                    }
                }
                ...
            ]
        '''
        coordinates = []
        for _id, aiv in self.__aivs.items():
            coordinates.append({
                'id': _id,
                'point': aiv.coordinate
            })
        return coordinates

    @property
    def aiv_infos(self):
        '''
            所有无人车的信息
            [
                {
                    'id' 
                    'battary' 
                    'status' 
                    'capacity' 
                    'taskid'
                    'position' 
                    'velocity',
                    'coordinate'
                },
                ...
            ]
        '''
        infos = []
        for _id, aiv in self.__aivs.items():
            infos.append(aiv.info)
        return infos

    @property
    def aiv_init_infos(self):
        '''
            所有无人车的信息
            [
                {
                    'id' 
                    'battary' 
                    'status' 
                    'capacity' 
                    'taskid'
                    'position' 
                },
                ...
            ]
        '''
        infos = []
        for _id, aiv in self.__aivs.items():
            infos.append(aiv.init_info)
        return infos

    @property
    def events(self):
        '''
            所有最近（不会太久远）发生的事件，结构如下
            [
                {
                    'time': 事件发生的时间,
                    'type': 事件类型,
                    'detail': 事件的具体细节信息
                },
                ...
            ]
        '''
        if not self.__events_happened:
            return None

        # 过滤掉已过时的事件
        while self.__now_time - self.__events_happened[0]['time'] > self.__outmode_time:
            # 删除第一个元素
            self.__events_happened.pop(0)
        
        # 取出事件
        events = self.__events_happened.copy()
        # 清空事件
        self.__events_happened.clear()
        # 返回取出的事件
        return events

    def dispatch(self, instructions):
        '''
        将产生的指令分发给场景中的 AIV
        '''
        if not type(instructions) is list:
            instructions = [instructions]
            
        for ins in instructions:
            aiv_id = ins.aiv_id
            self.__aivs[aiv_id].execute(ins)
            self.__moving_aivs.append(aiv_id)

    def __update_aivs(self):
        '''
        计算每一辆车的下一个位置、电量的消耗、一定概率随机故障等情况，更新车辆状态
        '''
        for _id, aiv in self.__aivs.items():
            aiv.update(self.now, self.__update_time)

    def __emit(self, event, params):
        if self.emit_event:
            self.emit_event(event, params)

    def __save__(self):
        pass

    def __load__(self):
        pass
